package com.huiruan.service;


import com.huiruan.entity.FileInfo;
import com.huiruan.exception.FileNotFoundException;
import com.huiruan.exception.FileStorageException;
import com.huiruan.property.FileStorageProperties;
import com.huiruan.utils.FileUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.util.FileSystemUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.net.MalformedURLException;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.time.Instant;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Stream;

@Service
public class FileStorageService {

    private final Path fileStorageLocation;
    private final List<String> allowedExtensions;
    private final int maxRetentionDays;
    private final boolean enableCompression;

    @Autowired
    public FileStorageService(FileStorageProperties fileStorageProperties) {
        this.fileStorageLocation = Paths.get(fileStorageProperties.getUploadDir())
                .toAbsolutePath().normalize();
        this.allowedExtensions = fileStorageProperties.getAllowedExtensions();
        this.maxRetentionDays = fileStorageProperties.getMaxRetentionDays();
        this.enableCompression = fileStorageProperties.isEnableCompression();

        try {
            Files.createDirectories(this.fileStorageLocation);
        } catch (Exception ex) {
            throw new FileStorageException("无法创建文件存储目录", ex);
        }
    }

    public FileInfo storeFile(MultipartFile file) {
        // 验证文件扩展名
        String fileExtension = FileUtil.getFileExtension(Objects.requireNonNull(file.getOriginalFilename()));
        if (!allowedExtensions.contains(fileExtension.toLowerCase())) {
            throw new FileStorageException("不支持的文件类型: " + fileExtension);
        }

        // 生成唯一文件名
        String uniqueFilename = FileUtil.generateUniqueFilename(file);

        try {
            // 检查文件名是否包含非法字符
            if (uniqueFilename.contains("..")) {
                throw new FileStorageException("文件名包含非法路径序列: " + uniqueFilename);
            }

            // 复制文件到目标位置
            Path targetLocation = this.fileStorageLocation.resolve(uniqueFilename);
            Files.copy(file.getInputStream(), targetLocation, StandardCopyOption.REPLACE_EXISTING);

            // 如果需要压缩文件
            String compressedSize = null;
            if (enableCompression && isCompressible(fileExtension)) {
                compressedSize = compressFile(targetLocation);
            }

            // 获取文件信息
            BasicFileAttributes attrs = Files.readAttributes(targetLocation, BasicFileAttributes.class);

            FileInfo fileInfo = new FileInfo();
            fileInfo.setFilename(uniqueFilename);
            fileInfo.setFileType(file.getContentType());
            fileInfo.setSize(file.getSize());
            fileInfo.setCompressedSize(compressedSize);
            fileInfo.setUploadTime(new Date(attrs.creationTime().toMillis()));
            fileInfo.setLastModified(new Date(attrs.lastModifiedTime().toMillis()));

            return fileInfo;
        } catch (IOException ex) {
            throw new FileStorageException("无法存储文件 " + uniqueFilename, ex);
        }
    }

    public Resource loadFileAsResource(String filename) {
        try {
            Path filePath = this.fileStorageLocation.resolve(filename).normalize();
            Resource resource = new UrlResource(filePath.toUri());
            if (resource.exists()) {
                return resource;
            } else {
                throw new FileNotFoundException("文件未找到: " + filename);
            }
        } catch (MalformedURLException ex) {
            throw new FileNotFoundException("文件未找到: " + filename, ex);
        }
    }

    public List<FileInfo> loadAllFiles() {
        try (Stream<Path> paths = Files.walk(this.fileStorageLocation, 1)) {
            List<FileInfo> fileInfos = new ArrayList<>();

            paths.filter(path -> !path.equals(this.fileStorageLocation))
                    .forEach(path -> {
                        try {
                            BasicFileAttributes attrs = Files.readAttributes(path, BasicFileAttributes.class);

                            FileInfo fileInfo = new FileInfo();
                            fileInfo.setFilename(path.getFileName().toString());
                            fileInfo.setFileType(Files.probeContentType(path));
                            fileInfo.setSize(attrs.size());
                            fileInfo.setUploadTime(new Date(attrs.creationTime().toMillis()));
                            fileInfo.setLastModified(new Date(attrs.lastModifiedTime().toMillis()));

                            fileInfos.add(fileInfo);
                        } catch (IOException e) {
                            throw new FileStorageException("无法读取文件信息", e);
                        }
                    });

            return fileInfos;
        } catch (IOException ex) {
            throw new FileStorageException("无法读取存储的文件", ex);
        }
    }

    public void deleteFile(String filename) {
        try {
            Path filePath = this.fileStorageLocation.resolve(filename).normalize();
            Files.deleteIfExists(filePath);
        } catch (IOException ex) {
            throw new FileStorageException("无法删除文件: " + filename, ex);
        }
    }

    public void deleteAllFiles() {
        try {
            FileSystemUtils.deleteRecursively(fileStorageLocation.toFile());
            FileUtil.createDirectoryIfNotExists(fileStorageLocation);
        } catch (IOException ex) {
            throw new FileStorageException("无法删除所有文件", ex);
        }
    }

    @Scheduled(cron = "0 0 3 * * ?") // 每天凌晨3点执行
    public void cleanupExpiredFiles() {
        if (maxRetentionDays <= 0) return;

        try {
            Files.walkFileTree(this.fileStorageLocation, new SimpleFileVisitor<Path>() {
                @Override
                public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                    Instant lastModifiedInstant = attrs.lastModifiedTime().toInstant();
                    LocalDate lastModifiedDate = lastModifiedInstant.atZone(ZoneId.systemDefault()).toLocalDate();
                    LocalDate cutoffDate = LocalDate.now().minusDays(maxRetentionDays);

                    if (lastModifiedDate.isBefore(cutoffDate)) {
                        Files.delete(file);
                    }
                    return FileVisitResult.CONTINUE;
                }

                @Override
                public FileVisitResult visitFileFailed(Path file, IOException exc) {
                    return FileVisitResult.CONTINUE;
                }
            });
        } catch (IOException ex) {
            throw new FileStorageException("清理过期文件失败", ex);
        }
    }

    private boolean isCompressible(String fileExtension) {
        return List.of("txt", "csv", "json", "xml", "log").contains(fileExtension.toLowerCase());
    }

    private String compressFile(Path filePath) throws IOException {
        // 这里实现文件压缩逻辑
        // 返回压缩后的大小
        return "压缩实现待完成";
    }
}